/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

package com.inspur.edp.lcm.metadata.common;

import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;


/**邻接矩阵的顶点类
 * @author xusy
 *
 * @param <T>
 */
public class Vertex<T> {

    /**
     * 顶点在图中唯一标识
     */
    private final String label;

    /**
     * 记录顶点内容
     */
    private final T content;

    /**
     * 这个顶点对应的子顶点<br>
     * 如果为有向图，则代表以这个顶点为起点的结束顶点
     */
    private final List<Vertex<T>> children;

    /**
     * 表示这个顶点是否已被访问，在bfs和dfs中会被使用到
     */
    private boolean visited;

    /**
     * 创建顶点
     * @param label  这个顶点的标识
     */
    public Vertex(String label){
        this.label=label;
        content = null;
        //用链表存储边
        children=new LinkedList<>();
        visited=false;
    }

    /**
     * 创建顶点
     * @param label  这个顶点的标识
     * @param content  这个顶点的内容
     */
    public Vertex(String label, T content){
        this.label=label;
        this.content = content;
        //用链表存储边
        children=new LinkedList<>();
        visited=false;
    }

    //下面与顶点的标识相关

    /**
     * 返回顶点的标识
     * @return 顶点的标识
     */
    public String getLabel() {
        return label;
    }

    /**
     * 返回顶点的内容
     * @return 顶点的标识
     */
    public T getContent() {
        return content;
    }

    /**
     * 根据顶点的标识确定是否是同一个顶点
     */
    @Override
    public boolean equals(Object otherVertex) {
        boolean result;
        //如果otherVertex为空或者类不同，直接返回false
        if(otherVertex==null||getClass()!=otherVertex.getClass()){
            return false;
        }
        //根据label确定是否是同一个顶点
        result=label.equals(((Vertex<?>)otherVertex).getLabel());
        return result;
    }

    //下面与顶点的边相关

    /**
     * 将这个顶点与endVertex连接
     * @param endVertex 待连接顶点
     * @return 如果顶点已经与endVertex连接，那么将会返回false<br>
     * 如果顶点没有与endVertex相连，则互相连接，返回true
     */
    public boolean connect(Vertex<T> endVertex){
        if (children.contains(endVertex)) {
            //如果顶点已经与endVertex连接，那么将会返回false
            return false;
        }
        //如果顶点没有与endVertex相连，则互相连接，返回true
        children.add(endVertex);
        return true;
    }

    /**
     * 将这个顶点与endVertex连接的边删除
     * @param endVertex 待解除连接顶点
     * @return  如果顶点已经与endVertex连接，那么将会删除这条边，返回true<br>
     * 如果顶点没有与endVertex连接，则啥都不做，返回false
     */
    public boolean disconnect(Vertex<T> endVertex){
        return children.remove(endVertex);
    }

    /**
     * 返回是否有以这个顶点为出发点,以endVertex为结束点的边
     * @return 如果有，返回起始顶点<br>
     * 如果没有，返回null
     */
    public Vertex<T> hasNeighbourVertex(Vertex<T> endVertex){
        Iterator<Vertex<T>> iterator = children.iterator();
        Vertex<T> vertex;
        while(iterator.hasNext()){
            vertex=iterator.next();
            if(vertex.equals(endVertex)){
                //如果顶点已经与endVertex连接，那么将返回这个边
                return vertex;
            }
        }
        //没有则返回null
        return null;
    }

    //下面是与顶点是否被访问相关
    /**
     * 返回顶点是否未被访问
     * @return 顶点是否未被访问
     */
    public boolean isNotVisited() {
        return !visited;
    }

    /**
     * 访问这个顶点
     */
    public void visit(){
        visited=true;
    }

    /**
     * 不访问这个顶点，或者说是清除访问状态
     */
    public void unVisit(){
        visited=false;
    }

    /**获得以这个顶点为出发点，相邻的第一个没有被访问的顶点
     * @return 如果没有，返回null<br>
     * 如果有，返回对应的顶点
     */
    public Vertex<T> getUnvisitedVertex(){
        Iterator<Vertex<T>> iterator = children.iterator();
        Vertex<T> vertex;
        while(iterator.hasNext()){
            vertex=iterator.next();
            if(vertex.isNotVisited()){
                return vertex;
            }
        }
        //没有则返回null
        return null;
    }

    public List<Vertex<T>> getChildren() {
        return children;
    }
}
